﻿using Core.Logger;
using Hardware.Reactor.Base;
using Hardware.Reactor.Base.Model;
using Hardware.Reactor.Base.Setting;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Hardware.Reactor.Default
{
    //192.168.1.203，502，
    //48=1号反应釜的浊度
    //49=2号反应釜的浊度

    /// <summary>
    /// 温度控制器
    /// </summary>
    class TempController : ReactiveObject, ITempController
    {
        private SerialPort serialPort = null;
        private TcpClient tcpClient = null;
        private ConcurrentQueue<byte[]> receiveQueue = new ConcurrentQueue<byte[]>();
        private ConcurrentQueue<byte[]> sendQueue = new ConcurrentQueue<byte[]>();
        private IReactorConfigProvider config;
        private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
        private byte[] command = new byte[] { 0x97, 0x76, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x30, 0x00, 0x02 };
        public TempController()
        {
            MessageObservable = this.WhenAnyValue(p => p.Message);
            Address48Observable = this.WhenAnyValue(p => p.Address48);
            Address49Observable = this.WhenAnyValue(p => p.Address49);
        }

        [Reactive]
        public bool Initialized { get; private set; }
        [Reactive]
        public bool Connected { get; private set; }
        [Reactive]
        public string Message { get; private set; }

        public IObservable<string> MessageObservable { get; }
        [Reactive]
        public short Address48 { get; private set; }
        [Reactive]
        public short Address49 { get; private set; }

        public IObservable<short> Address48Observable { get; }

        public IObservable<short> Address49Observable { get; }

        public ConnectionMode ConnectionMode { get; private set; }

        public bool Init(IReactorConfigProvider config, ConnectionMode connectionMode = ConnectionMode.串口)
        {
            this.config = config;
            this.ConnectionMode = connectionMode;
            bool result = false;

            try
            {
                if (ConnectionMode == ConnectionMode.串口)
                {
                    if (serialPort == null)
                    {
                        serialPort = new SerialPort(config.ReactorConfig.TempControllerPortName, config.ReactorConfig.TempControllerBaudRate); ;
                        serialPort.Open();
                    }

                    if(serialPort.IsOpen)
                    {
                        Initialized = serialPort.IsOpen;
                    }

                    Connected = serialPort.IsOpen;


                }
                else
                {
                    if(tcpClient== null)
                    {
                        tcpClient = new TcpClient();
                        tcpClient.ConnectAsync(config.ReactorConfig.TempControllerIP, config.ReactorConfig.TempControllerPort).Wait(3000);
                    }

                    if(tcpClient.Connected)
                    {
                        Initialized=tcpClient.Connected;                        
                    }

                    Connected = tcpClient.Connected;

                }

                if(connectionMode == ConnectionMode.串口)
                {
                    //串口接收数据订阅回调函数
                    serialPort.DataReceived += (s, e) =>
                    {
                        Thread.Sleep(15);
                        int length = serialPort.BytesToRead;
                        byte[] buffer = new byte[length];
                        serialPort.Read(buffer, 0, length);//读取串口缓冲区的数据
                        receiveQueue.Enqueue(buffer);//入队
                    };
                }

                Task.Factory.StartNew(ReceiveTask);//TCP接收线程
                Task.Factory.StartNew(AnalysisTask);//处理数据
                Task.Factory.StartNew(ReadTask);//读取反应釜浊度
                Task.Factory.StartNew(SendTask);//下发指令线程
            }
            catch (Exception ex)
            {
                Logs.LogError(ex);
            }



            return result;
        }

        private void SendTask()
        {
            while(!cancellationTokenSource.Token.IsCancellationRequested)
            {
                try
                {
                    var result = sendQueue.TryDequeue(out byte[] command);
                    if (result)
                    {
                        if (CheckConnection())
                        {
                            switch (ConnectionMode)
                            {
                                case ConnectionMode.串口:
                                    serialPort.Write(command, 0, command.Length);
                                    break;
                                case ConnectionMode.网口:
                                    tcpClient.Client.Send(command);
                                    break;
                                default: break;
                            }
                        }

                        Task.Delay(25).Wait();
                    }
                    else
                    {
                        Task.Delay(2).Wait();
                    }
                }
                catch(Exception ex)
                {
                    throw ex;
                }
            }
        }

        /// <summary>
        /// 读取反应釜浊度
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private void ReadTask()
        {
            while (!cancellationTokenSource.Token.IsCancellationRequested)
            {
                Thread.Sleep(1000);
                if (CheckConnection())
                {
                    Send(command);
                }
            }
        }

        /// <summary>
        /// 消费接收数据的队列
        /// </summary>
        private void AnalysisTask()
        {
            while (!cancellationTokenSource.Token.IsCancellationRequested)
            {
                var result = receiveQueue.TryDequeue(out byte[] receiveBytes);
                if (result)
                {
                    DoAnalysis(receiveBytes);
                }
                else
                {
                    Task.Delay(2).Wait();
                }
            }
        }

        /// <summary>
        /// 只解析地址48 49 两个内容
        /// </summary>
        /// <param name="receiveBytes"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void DoAnalysis(byte[] receiveBytes)
        {
            if (receiveBytes == null) return;
            if(receiveBytes.Length == 0) return;
            if (receiveBytes.Length == 13)
            {
                byte[] v = new byte[2];
                v[0] = receiveBytes[10];
                v[1] = receiveBytes[9];
                this.Address48 = BitConverter.ToInt16(v, 0);

                v[0] = receiveBytes[12];
                v[1] = receiveBytes[11];
                this.Address49 = BitConverter.ToInt16(v, 2);
            }
        }

        private void ReceiveTask()
        {
            if (ConnectionMode == ConnectionMode.串口) return;
            while (!cancellationTokenSource.Token.IsCancellationRequested)
            {
                try
                {
                    if (tcpClient == null)
                    {
                        break;
                    }

                    if (tcpClient.Available <= 0)
                    {
                        Task.Delay(2).Wait();
                        continue;
                    }

                    byte[] buffer = new byte[256];//最大长度
                    int length = tcpClient.Client.Receive(buffer);//阻塞
                    byte[] receiveBytes = buffer.Take(length).ToArray();//实际长度
                    receiveQueue.Enqueue(receiveBytes);//入队
                }
                catch(Exception ex)
                {
                    throw new Exception(ex.Message);
                }

            }
        }

        public bool CheckConnection()
        {
            switch (ConnectionMode)
            {
                case ConnectionMode.串口:
                    if (serialPort != null)
                    {
                        Connected = serialPort.IsOpen;
                    }
                    break;
                case ConnectionMode.网口:
                    if (!tcpClient.Connected)
                    {
                        tcpClient.ConnectAsync(config.ReactorConfig.TempControllerIP, config.ReactorConfig.TempControllerPort).Wait(3000);
                    }
                    Connected = tcpClient.Connected;
                    break;
                default: break;
            }

            return Connected;
        }

        public void Close()
        {
            cancellationTokenSource.Cancel();

            Task.Delay(50).ContinueWith(p =>
            {
                if (tcpClient != null)
                {
                    tcpClient.Close();
                    tcpClient = null;
                }

                if(serialPort!= null)
                {
                    serialPort.Close();
                    serialPort = null;
                }
            });
        }

        

        public bool Send(byte[] data)
        {
            sendQueue.Enqueue(data);

            return true;
        }
    }
}
